package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.api.constant.MemberRightAcquireWayEnum;
import com.ssy.lingxi.member.merchant.api.constant.MemberRightParamWayEnum;
import com.ssy.lingxi.member.merchant.api.constant.MemberRightTypeEnum;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.LevelBO;
import com.ssy.lingxi.member.merchant.model.constant.MemberValidateStatusEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.LevelAndTagVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.MemberRightScoreVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.RoleIdAndNameVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberDetailRightConfigVO;
import com.ssy.lingxi.member.merchant.repository.MemberLevelConfigRepository;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberLevelConfigService;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * 会员等级配置（内部工具类）相关接口
 * @author 万宁
 * @version 2.0.0
 * @date 2022-03-23
 */
@Service
public class BaseMemberLevelConfigServiceImpl implements IBaseMemberLevelConfigService {
    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private MemberLevelConfigRepository memberLevelConfigRepository;

    @Resource
    private JPAQueryFactory jpaQueryFactory;

    /**
     * 是否存在等级配置
     *
     * @param memberId  上级会员Id
     * @param roleId    上级会员角色Id
     * @param subRoleId 下级会员角色Id
     * @param level     等级
     * @return 存在-ture，不存在-false
     */
    @Override
    public Boolean existLevel(Long memberId, Long roleId, Long subRoleId, Integer level) {
        return memberLevelConfigRepository.existsByMemberIdAndRoleIdAndSubRoleIdAndLevelAndStatus(memberId, roleId, subRoleId, level, EnableDisableStatus.ENABLE.getCode());
    }

    /**
     * 查询指定等级
     *
     * @param relationDO    会员关系
     * @param specificLevel 指定的等级
     * @return 指定等级，如果没有返回Null
     */
    @Override
    public MemberLevelConfigDO findLevel(MemberRelationDO relationDO, Integer specificLevel) {
        return findLevel(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRoleId(), specificLevel);
    }

    /**
     * 查询指定等级
     *
     * @param memberId      上级会员Id
     * @param roleId        上级会员角色Id
     * @param subRoleId     下级会员角色Id
     * @param specificLevel 指定的等级
     * @return 指定等级，如果没有返回Null
     */
    @Override
    public MemberLevelConfigDO findLevel(Long memberId, Long roleId, Long subRoleId, Integer specificLevel) {
        return memberLevelConfigRepository.findFirstByMemberIdAndRoleIdAndSubRoleIdAndLevel(memberId, roleId, subRoleId, specificLevel);
    }

    /**
     * 查询最小等级配置
     *
     * @param relationDO 会员关系
     * @return 最小等级配置，如没有配置返回Null
     */
    @Override
    public MemberLevelConfigDO findFirstLevel(MemberRelationDO relationDO) {
        return findFirstLevel(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRoleId());
    }

    /**
     * 最小等级配置
     *
     * @param memberId  上级会员Id
     * @param roleId    上级会员角色Id
     * @param subRoleId 下级会员角色Id
     * @return 最小等级配置，如没有配置返回Null
     */
    @Override
    public MemberLevelConfigDO findFirstLevel(Long memberId, Long roleId, Long subRoleId) {
        return memberLevelConfigRepository.findFirstByMemberIdAndRoleIdAndSubRoleIdAndStatus(memberId, roleId, subRoleId, EnableDisableStatus.ENABLE.getCode(), Sort.by("level").ascending());
    }

    /**
     * 查询下级会员的下一等级标签
     *
     * @param relationDO 会员关系
     * @param levelDO    下级会员当前等级
     * @return 下一等级标签，如无下一等级返回空字符串
     */
    @Override
    public String findNextLevelTag(MemberRelationDO relationDO, MemberLevelRightDO levelDO) {
        return findNextLevelTag(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRoleId(), levelDO.getLevel());
    }

    /**
     * 查询下级会员的下一等级标签
     *
     * @param memberId     上级会员Id
     * @param roleId       上级会员角色Id
     * @param subRoleId    下级会员角色Id
     * @param currentLevel 下级会员当前等级
     * @return 下一等级标签，如无下一等级返回空字符串
     */
    @Override
    public String findNextLevelTag(Long memberId, Long roleId, Long subRoleId, Integer currentLevel) {
        return findNextLevel(memberId, roleId, subRoleId, currentLevel).getNextTag();
    }

    /**
     * 查询下级会员的下一等级标签及升级阈值
     *
     * @param memberId     上级会员Id
     * @param roleId       上级会员角色Id
     * @param subRoleId    下级会员角色Id
     * @param currentLevel 下级会员当前等级
     * @return 下一等级标签，如无下一等级返回空字符串
     */
    @Override
    public LevelBO findNextLevel(Long memberId, Long roleId, Long subRoleId, Integer currentLevel) {
        Specification<MemberLevelConfigDO> specification = (Specification<MemberLevelConfigDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), memberId));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), roleId));
            list.add(criteriaBuilder.equal(root.get("subRoleId").as(Long.class), subRoleId));
            list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
            list.add(criteriaBuilder.greaterThan(root.get("level").as(Integer.class), currentLevel));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        LevelBO levelBO = new LevelBO();
        List<MemberLevelConfigDO> levelConfigDOList = memberLevelConfigRepository.findAll(specification);
        if (!CollectionUtils.isEmpty(levelConfigDOList)) {
            MemberLevelConfigDO nextConfig = levelConfigDOList.stream().min(Comparator.comparing(MemberLevelConfigDO::getLevel)).orElse(null);
            if (nextConfig != null) {
                levelBO.setNextTag(nextConfig.getLevelTag());
                levelBO.setNextScore(nextConfig.getPoint());
            }
        }

        return levelBO;
    }


    /**
     * 查询下级会员等级列表，转换为前端下拉框选项
     *
     * @param memberId 上级会员Id
     * @param roleId   上级会员角色Id
     * @return 下拉框选项
     */
    @Override
    public List<LevelAndTagVO> listSubMemberLevels(Long memberId, Long roleId) {
        return memberLevelConfigRepository.findByMemberIdAndRoleIdAndStatus(memberId, roleId, EnableDisableStatus.ENABLE.getCode()).stream().map(memberLevelConfigDO -> new LevelAndTagVO(memberLevelConfigDO.getLevel(), memberLevelConfigDO.getLevelTag()))
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LevelAndTagVO::getLevel))), ArrayList::new))
                .stream().distinct().sorted(Comparator.comparing(LevelAndTagVO::getLevel)).collect(Collectors.toList());
    }

    /**
     * 查询下级会员等级列表，转换为前端下拉框选项
     *
     * @param memberId  上级会员Id
     * @param roleId    上级会员角色Id
     * @param subRoleId 下级会员角色Id
     * @return 下拉框选项
     */
    @Override
    public List<LevelAndTagVO> listSubMemberLevels(Long memberId, Long roleId, Long subRoleId) {
        return memberLevelConfigRepository.findByMemberIdAndRoleIdAndSubRoleIdAndStatus(memberId, roleId, subRoleId, EnableDisableStatus.ENABLE.getCode()).stream().map(memberLevelConfigDO -> new LevelAndTagVO(memberLevelConfigDO.getLevel(), memberLevelConfigDO.getLevelTag()))
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LevelAndTagVO::getLevel))), ArrayList::new))
                .stream().sorted(Comparator.comparing(LevelAndTagVO::getLevel)).collect(Collectors.toList());
    }

    /**
     * （新增下级会员时）查询下级会员等级列表，转换为前端下拉框选项
     *
     * @param memberId     上级会员Id
     * @param roleId       上级会员角色Id
     * @param subRoleId    下级会员角色Id
     * @param memberTypeId 会员类型Id（不是枚举）
     * @return 下拉框选项
     */
    @Override
    public List<LevelAndTagVO> listSubMemberLevels(Long memberId, Long roleId, Long subRoleId, Long memberTypeId) {
        QMemberLevelConfigDO qMemberLevelConfig = QMemberLevelConfigDO.memberLevelConfigDO;
        QRoleDO qRole = QRoleDO.roleDO;
        QMemberTypeDO qMemberType = QMemberTypeDO.memberTypeDO;

        return jpaQueryFactory.selectDistinct(Projections.constructor(LevelAndTagVO.class, qMemberLevelConfig.level, qMemberLevelConfig.levelTag))
                .from(qMemberLevelConfig)
                .leftJoin(qRole).on(qMemberLevelConfig.subRoleId.eq(qRole.id))
                .leftJoin(qMemberType).on(qRole.memberType.id.eq(qMemberType.id))
                .where(qMemberLevelConfig.memberId.eq(memberId).and(qMemberLevelConfig.roleId.eq(roleId)).and(qMemberLevelConfig.subRoleId.eq(subRoleId)))
                .where(qMemberType.id.eq(memberTypeId))
                .orderBy(qMemberLevelConfig.level.asc())
                .fetch();
    }

    /**
     * 查询会员平台通用、会员专有的权益积分
     *
     * @param upperMemberId 上级会员Id
     * @param upperRoleId   上级会员角色Id
     * @param subMemberId   下级会员Id
     * @param subRoleId     下级会员角色Id
     * @return 查询结果
     */
    @Override
    public Wrapper<MemberRightScoreVO> getMemberRightPoint(Long upperMemberId, Long upperRoleId, Long subMemberId, Long subRoleId) {
        MemberRelationDO platformRelationDO = relationRepository.findFirstBySubMemberIdAndSubRoleIdAndRelType(subMemberId, subRoleId, MemberRelationTypeEnum.PLATFORM.getCode());
        if (platformRelationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberRightScoreVO scoreVO = new MemberRightScoreVO();
        if(platformRelationDO.getLevelRight() == null) {
            scoreVO.setPlatformScore(0);
        } else {
            if (!platformRelationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()) || !platformRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode())) {
                scoreVO.setPlatformScore(0);
            } else {
                scoreVO.setPlatformScore(platformRelationDO.getLevelRight().getCurrentPoint());
            }
        }

        MemberRelationDO relationDO = relationRepository.findFirstByMemberIdAndRoleIdAndSubMemberIdAndSubRoleId(upperMemberId, upperRoleId, subMemberId, subRoleId);
        if (relationDO == null || relationDO.getLevelRight() == null || !relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()) || !relationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode())) {
            scoreVO.setMemberScore(0);
        } else {
            scoreVO.setMemberScore(relationDO.getLevelRight().getCurrentPoint());
        }

        return Wrapper.success(scoreVO);
    }

    /**
     * 查询会员最低等级的权益列表
     *
     * @param upperMemberId 上级会员Id
     * @param upperRoleId   上级会员角色Id
     * @param subRoleId     下级会员角色Id
     * @return 查询结果
     */
    @Override
    public List<MemberDetailRightConfigVO> findSubMemberRights(Long upperMemberId, Long upperRoleId, Long subRoleId) {
        MemberLevelConfigDO levelConfigDO = memberLevelConfigRepository.findByMemberIdAndRoleIdAndSubRoleIdAndStatus(upperMemberId, upperRoleId, subRoleId, EnableDisableStatus.ENABLE.getCode()).stream().min(Comparator.comparingInt(MemberLevelConfigDO::getLevel)).orElse(null);
        if(levelConfigDO == null) {
            return new ArrayList<>();
        }

        if(CollectionUtils.isEmpty(levelConfigDO.getRights())) {
            return new ArrayList<>();
        }

        return levelConfigDO.getRights().stream().map(right -> {
            MemberDetailRightConfigVO configVO = new MemberDetailRightConfigVO();
            configVO.setId(right.getId());
            configVO.setRightTypeEnum(right.getRightType());
            configVO.setName(MemberRightTypeEnum.getCodeMsg(right.getRightType()));
            configVO.setRemark(MemberRightTypeEnum.getRemark(right.getRightType()));
            configVO.setAcquireWay(MemberRightAcquireWayEnum.getCodeMsg(right.getAcquireWay()));
            configVO.setParamWay(MemberRightParamWayEnum.getCodeMsg(right.getParamWay()));
            configVO.setStatus(right.getStatus());
            String param = String.format("%.2f", right.getParameter().multiply(new BigDecimal(100)).doubleValue()).concat("%");
            configVO.setParameter(param);
            return configVO;
        }).collect(Collectors.toList());
    }

    /**
     * 查询会员等级配置的下级会员角色Id和角色名称列表（去重）
     *
     * @param memberId 上级会员Id
     * @param roleId   上级会员角色Id
     * @return 查询结果
     */
    @Override
    public List<RoleIdAndNameVO> findLevelConfigRoles(Long memberId, Long roleId) {
        QMemberLevelConfigDO qMemberLevelConfig = QMemberLevelConfigDO.memberLevelConfigDO;
        QRoleDO qRole = QRoleDO.roleDO;

        JPAQuery<RoleIdAndNameVO> query = jpaQueryFactory.select(Projections.constructor(RoleIdAndNameVO.class, qRole.id, qRole.roleName))
                .from(qMemberLevelConfig).leftJoin(qRole).on(qMemberLevelConfig.subRoleId.eq(qRole.id))
                .where(qMemberLevelConfig.memberId.eq(memberId).and(qMemberLevelConfig.roleId.eq(roleId)));

        return query.fetch().stream().distinct().collect(Collectors.toList());
    }
}
